2014/12/25

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

golang には go build というビルド機能があり、C言語と golang をまぜた cgo というC言語拡張も同じコマンドでビルド出来ます。

その際、ソースコードのコメントに CFLAGS や LDFLAGS を自ら指定する事が出来るので

package gtk

// #include "gtk.go.h"
// #cgo pkg-config: gtk+-2.0
import "C"
import (
    "fmt"
    "log"
    "reflect"
    "runtime"
    "strings"
    "unsafe"

    "github.com/mattn/go-gtk/gdk"
    "github.com/mattn/go-gtk/gdkpixbuf"
    "github.com/mattn/go-gtk/glib"
    "github.com/mattn/go-gtk/pango"
)

上記は go-gtk のコードの一部。

そのライブラリやアプリケーションをビルドしたいユーザは特にライブラリへのパスを指定する事なく、ただ単に

go build

と実行するだけで実行モジュールが出来上がります。この便利さに目を付けた Pietro Gagliardi さんが qo という golang で書かれたプログラムを公開してくれています。

andlabs/qo · GitHub

Another build system for C/C++, I guess? Inspired by 'go build'

https://github.com/andlabs/qo

インストールは golang がインストールされている状態であれば

go get github.com/andlabs/qo

だけです。昔 golang のリポジトリから Makefile が消え去り ビルド構成ファイルが何もないという状況を見て軽いカルチャーショックを受けたのだけど、今となってはとても心地良いし「あー、Makefile いらんかったんやー」とも思います。その心地よさを C/C++ で扱えるツールです。例えば gtk を使ったプログラムを書く場合

#include <gtk/gtk.h>

int
main(int argc, char* argv[]) {
  GtkWidget* window;
  GtkWidget* label;
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "helloworld");
  g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, window);
  label = gtk_label_new("Hello World!");
  gtk_container_add(GTK_CONTAINER(window), label);
  gtk_widget_show_all(window);
  gtk_main();
  return 0;
}
pkg-config というツールを使いますが、このツールから得られた CFLAGS や LDFLAGS をコマンドラインに渡すか、以下の様な Makefile が必要でした。

SRCS \
    foo.c

OBJS $(subst .c,.o,$(SRCS))

CFLAGS `pkg-config --cflags gtk+-2.0`
LIBS `pkg-config --libs gtk+-2.0`
TARGET = qo-sandbox

all : $(TARGET)

$(TARGET) : $(OBJS)
    gcc -o $@ $(OBJS) $(LIBS)

.c.o :
    gcc -c $(CFLAGS) -I. $< -o $@

clean :
    rm -f *.o $(TARGET)

しかし qo を使うと Makefile は消して良く、以下の様なコメントを書くだけで良いのです。

// #qo pkg-config: gtk+-2.0
#include <gtk/gtk.h>

int
main(int argc, char* argv[]) {
  GtkWidget* window;
  GtkWidget* label;
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "helloworld");
  g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, window);
  label = gtk_label_new("Hello World!");
  gtk_container_add(GTK_CONTAINER(window), label);
  gtk_widget_show_all(window);
  gtk_main();
  return 0;
}

あとはおもむろに

qo

を実行するだけです。毎回フルビルドするのではなく .qoobj というフォルダにビルド済みのファイルが格納されるので更新されたファイルのみビルドされます。また CFLAGS や LDFLAGS も直接指定する事が出来ます。

// #qo CFLAGS: -I/opt/sqlite3/include
// #qo LIBS: sqlite3
さらに golang の go build と同様に、ファイル名に _windows が付いている物は windows のみ、_386 が付いている物は 386 系 CPU のみビルド対象となります。(サポートOS: windows, darwin, linux, freebsd, openbsd, netbsd, dragonfly, solaris)

リンクされる実行モジュールはディレクトリ名という割り切りなので、覚えてしまえば面倒臭さがなくなりとても心地よいです。

Makefile ほど細かな設定は出来ないですが、ちょっとした小さいプログラムを書きあげる際にとても便利なツールとなる事は間違いないと思います。

Posted at by